package com.fowo.api.service.handleWork;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.fowo.api.entity.ReceiptProduct;
import com.fowo.api.entity.StockIn;
import com.fowo.api.entity.StockInProduct;
import com.fowo.api.entity.WarehouseBin;
import com.fowo.api.inventory.model.InventoryExchangeVo;
import com.fowo.api.inventory.model.PatternEnum;
import com.fowo.api.inventory.model.SimpleInventoryItem;
import com.fowo.api.inventory.model.TargetTypeEnum;
import com.fowo.api.inventory.model.form.InventoryExchangeFormVo;
import com.fowo.api.inventory.service.InventoryBusinessService;
import com.fowo.api.mapper.StockInMapper;
import com.fowo.api.mapper.StockInProductMapper;
import com.fowo.api.mapper.WarehouseBinMapper;
import com.fowo.api.model.quality.QualityCheckInventoryVo;
import com.fowo.api.model.quality.check.storage.QualityCheckStorageRevocationAction;
import com.fowo.api.model.quality.check.storage.QualityCheckStorageVo;
import com.fowo.api.model.receipt.ReceiptVo;
import com.fowo.api.service.impl.QualityCheckStorageServiceImpl;
import com.fowo.api.service.impl.ReceiptProductServiceImpl;
import com.fowo.api.service.impl.ReceiptServiceImpl;
import com.fowo.api.user.model.JwtUserInfo;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class QualityCheckStorageRevocation implements QualityCheckStorageRevocationAction {

    @Resource
    private QualityCheckStorageServiceImpl qualityCheckStorageService;
    @Resource
    private ReceiptProductServiceImpl receiptProductService;
    @Resource
    private ReceiptServiceImpl receiptService;
    @Resource
    private StockInProductMapper stockInProductMapper;
    @Resource
    private StockInMapper stockInMapper;
    @Resource
    private WarehouseBinMapper warehouseBinMapper;
    @Resource
    private InventoryBusinessService inventoryBusinessService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void run(Long id) throws Exception {
        QualityCheckStorageVo qualityCheckStorageVo = qualityCheckStorageService.getVoById(id);

        // 更新收货单
        ReceiptProduct receiptProduct = receiptProductService.getById(qualityCheckStorageVo.getReceiptProductId());
        Assert.notNull(receiptProduct,"收货单不存在，请联系管理员！");
        receiptProduct.setProductGoodNum((receiptProduct.getProductGoodNum() == null ? 0 : receiptProduct.getProductGoodNum()) - qualityCheckStorageVo.getProductGoodNum());
        receiptProduct.setProductBadNum((receiptProduct.getProductBadNum() == null ? 0 : receiptProduct.getProductBadNum()) - qualityCheckStorageVo.getProductBadNum());
        receiptProduct.setTestedQuantity((receiptProduct.getTestedQuantity() == null ? 0 : receiptProduct.getTestedQuantity()) - qualityCheckStorageVo.getProductReceiveNum());
        receiptProduct.setQcStatus("0");
        receiptProduct.setNoQcNum(receiptProduct.getNoQcNum() + qualityCheckStorageVo.getProductReceiveNum());
//        receiptProduct.setReflecti(receiptProduct.getReflecti() - jsonObject.getInteger("productReceiveNum"));
        receiptProduct.setQsMessage(0L);
        receiptProduct.setLowQuality(receiptProduct.getLowQuality() + qualityCheckStorageVo.getProductReceiveNum());
        receiptProduct.setLastUpdateTime(new Date());
        receiptProductService.updateById(receiptProduct);

        final ReceiptVo receiptVo = receiptService.getVoById(receiptProduct.getParentReceipt());
        // 更新入库单
        final StockIn stockIn = stockInMapper.selectOne(Wrappers.lambdaQuery(StockIn.class)
                .eq(StockIn::getAssociatedPo, receiptVo.getOrderSn())
                .eq(StockIn::getWarehouse, qualityCheckStorageVo.getWarehouse()));
        Assert.notNull(stockIn,"入库单不存在，请联系管理员！");
        StockInProduct stockInProduct = stockInProductMapper.selectOne(Wrappers.lambdaQuery(StockInProduct.class)
                .eq(StockInProduct::getParentStockInId, stockIn.getId())
                .eq(StockInProduct::getProductId, qualityCheckStorageVo.getProductName()));
        Assert.notNull(stockInProduct,"入库单产品不存在，请联系管理员！");


        final WarehouseBin warehouseBin = warehouseBinMapper.selectById(qualityCheckStorageVo.getWhbCodeGoodId());
        Assert.notNull(warehouseBin,"仓位不存在，请重新设置！");

        final WarehouseBin waitBin = warehouseBinMapper.selectOne(Wrappers.lambdaQuery(WarehouseBin.class)
                .eq(WarehouseBin::getType, "1")
                .eq(WarehouseBin::getWarehouseId, qualityCheckStorageVo.getWarehouse()));
        Assert.notNull(waitBin,"待检暂存不存在！");

        Integer quantity = Convert.toInt(stockInProduct.getQuantity(), 0);
        stockInProduct.setQuantity(quantity - qualityCheckStorageVo.getProductGoodNum());

        Integer defectiveProduct = Convert.toInt(stockInProduct.getDefectiveProduct(), 0);
        stockInProduct.setDefectiveProduct(defectiveProduct - qualityCheckStorageVo.getProductBadNum());

        stockInProduct.setWaitQuantity(stockInProduct.getWaitQuantity() + qualityCheckStorageVo.getProductReceiveNum().intValue());

        Integer waitPutaway = Convert.toInt(stockInProduct.getWaitPutaway(), 0);
        stockInProduct.setWaitPutaway(warehouseBin.getType().equals("5") ? waitPutaway : (waitPutaway - qualityCheckStorageVo.getProductGoodNum()));


        stockInProduct.setPositions(waitBin.getId());
        stockInProduct.setDefectiveProductPosition(waitBin.getId());
        stockInProductMapper.updateById(stockInProduct);

        qualityCheckStorageVo.setQcStatus("3");
        qualityCheckStorageService.update(qualityCheckStorageVo);

        changeBin(qualityCheckStorageVo,waitBin.getId());

    }

    /**
     * 库存转移
     * @param qualityCheckStorageVo
     * @param toBinId
     * @throws Exception
     */
    public void changeBin(QualityCheckStorageVo qualityCheckStorageVo,Long toBinId) throws Exception {
        QualityCheckInventoryVo model = new QualityCheckInventoryVo();
        model.setId(qualityCheckStorageVo.getId());
        model.setQcSn(qualityCheckStorageVo.getQcSn());
        model.setWid(qualityCheckStorageVo.getWarehouse());
        model.setShopId(qualityCheckStorageVo.getShop());
        model.setFnskuName(qualityCheckStorageVo.getFnsku());
        model.setProductId(qualityCheckStorageVo.getProductName());
        model.setToBinId(toBinId);

        // 良品移库
        model.setFromBinId(qualityCheckStorageVo.getWhbCodeGoodId());
        model.setQuantity(qualityCheckStorageVo.getProductGoodNum().longValue());
        model.setTarget(TargetTypeEnum.Normal);

        inventoryBusinessService.exchange(prepareFinishPickingInventory(model));

        InventoryExchangeFormVo goodFormVo = prepareInventoryTurnover(model);
        inventoryBusinessService.exchange(goodFormVo);

        // 次品移库
        model.setFromBinId(qualityCheckStorageVo.getWhbCodeBadId());
        model.setQuantity(qualityCheckStorageVo.getProductBadNum().longValue());
        model.setTarget(TargetTypeEnum.Defect);

        inventoryBusinessService.exchange(prepareFinishPickingInventory(model));

        InventoryExchangeFormVo badFormVo = prepareInventoryTurnover(model);
        inventoryBusinessService.exchange(badFormVo);
    }

    /**
     * 仓库转移
     * @param vo
     * @return
     * @throws Exception
     */
    protected InventoryExchangeFormVo prepareFinishPickingInventory(QualityCheckInventoryVo vo) throws Exception {
        JwtUserInfo jwtUserInfo = JwtUserInfo.fromHeader();
        InventoryExchangeFormVo formVo = new InventoryExchangeFormVo();
        formVo.setSupportNegative(true);
        formVo.setFrom(vo.getTarget());
        formVo.setTo(TargetTypeEnum.Inspected);
        formVo.setFormNum(vo.getQcSn());
        formVo.setFormOperator(jwtUserInfo.getUserId().toString());
        formVo.setDocumentType("撤销质检移库");
        if(ObjectUtils.isEmpty(vo.getWid())){
            throw new Exception("出仓库 为空");
        }
        formVo.setFromStockId(vo.getWid());
        if(ObjectUtils.isEmpty(vo.getWid())){
            throw new Exception("入仓库 为空");
        }
        formVo.setToStockId(vo.getWid());
        formVo.setModel(PatternEnum.FIFO);

        SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
        inventoryItem.setId(vo.getProductId());
        InventoryExchangeVo exchangeItem = new InventoryExchangeVo();
        exchangeItem.setItem(inventoryItem);
        exchangeItem.setQty(BigDecimal.valueOf(vo.getQuantity()));
        exchangeItem.setShopId(String.valueOf(vo.getShopId()).equals("null")? null:String.valueOf(vo.getShopId()));
        exchangeItem.setFnSku( String.valueOf(vo.getFnskuName()).equals("null")? null:String.valueOf(vo.getFnskuName()));
        exchangeItem.setCustomId(vo.getId());
        exchangeItem.setCustomBdId(null);
        formVo.add(exchangeItem);
        return formVo;
    }

    /**
     * 仓位转移
     * @param vo
     * @return
     * @throws Exception
     */
    protected InventoryExchangeFormVo prepareInventoryTurnover(QualityCheckInventoryVo vo) throws Exception {
        JwtUserInfo jwtUserInfo = JwtUserInfo.fromHeader();

        InventoryExchangeFormVo formVo = new InventoryExchangeFormVo();
        formVo.setFrom(TargetTypeEnum.Inspected);
        formVo.setTo(TargetTypeEnum.Inspected);
        formVo.setFormNum(vo.getQcSn());
        formVo.setFormOperator(jwtUserInfo.getUserId().toString());
        formVo.setFromStockId(vo.getWid());
        formVo.setToStockId(vo.getWid());
        formVo.setModel(PatternEnum.FIFO);
        formVo.setDocumentType("撤销质检移库");

        SimpleInventoryItem inventoryItem = new SimpleInventoryItem();
        inventoryItem.setId(vo.getProductId());
        InventoryExchangeVo exchangeItem = new InventoryExchangeVo();
        exchangeItem.setItem(inventoryItem);
        exchangeItem.setQty(BigDecimal.valueOf(vo.getQuantity()));
        exchangeItem.setShopId(
                String.valueOf(vo.getShopId()).equals("null")
                        ? null
                        : String.valueOf(vo.getShopId())
        );
        exchangeItem.setFnSku(
                String.valueOf(vo.getFnskuName()).equals("null")
                        ? null
                        : String.valueOf(vo.getFnskuName())
        );
        Map<Long, Integer> binIds = new HashMap<>();
        binIds.put(
                vo.getFromBinId(),
                Integer.parseInt(
                        String.valueOf(vo.getQuantity()).equals("null")
                                ? "0"
                                : String.valueOf(vo.getQuantity())
                )
        );
        exchangeItem.setFromBinIds(binIds);
        Map<Long, Integer> toBinIds = new HashMap<>();
        toBinIds.put(
                vo.getToBinId(),
                Integer.parseInt(
                        String.valueOf(vo.getQuantity()).equals("null")
                                ? "0"
                                : String.valueOf(vo.getQuantity())
                )
        );
        exchangeItem.setToBinIds(toBinIds);
        exchangeItem.setFromBinIdsType(TargetTypeEnum.Normal);
        exchangeItem.setToBinIdsType(TargetTypeEnum.Normal);
        exchangeItem.setCustomId(vo.getId());
        exchangeItem.setCustomBdId(null);
        formVo.add(exchangeItem);
        return formVo;
    }
}
